#include "ASEntity.h"
#include "ASComponent.h"

NS_AS_BEGIN

//ASEntityInitData::ASEntityInitData(int i,int f)
//:_nAttrsNumI(i)
//,_nAttrsNumF(f)
//{}
//ASEntityInitData::~ASEntityInitData()
//{}


ASEntity::ASEntity(int nAttrsNumI ,int nAttrsNumF ,const ASEntityMobileData* pMobiledata)
:_pAttribute(nullptr)
,_iBoundRadius(0)
,_iDetechRadius(0)
,_iAttackRadius(0)
,_iCollideFlag(0)
,_iAlignOrder(0)
,_iTypeID(0)
,_bComsLocked(false)
,_bTag(false)
,_bActive(true)
{
	_vHeading = pMobiledata?pMobiledata->_vHeading:Vector2D(0,1);
	_vSide = _vHeading.Perp();
	_dMass = pMobiledata?pMobiledata->_dMass:99999999;
	_dMassInv = 1/_dMass;
	_dMaxSpeed = pMobiledata?pMobiledata->_dMaxspeed:0.0;
	_dMaxForce = pMobiledata?pMobiledata->_dMaxForce:0.0;
	_dMaxTurnRate = pMobiledata?pMobiledata->_dMaxTurnRate:Pi;

	_pAttribute = new ASEntityAttribute(nAttrsNumI,nAttrsNumF);
}

ASEntity::~ASEntity()
{
	removeAllComponent();
}

void ASEntity::destory()
{
	setActive(false);
	if (!isComsLocked())
	{
		removeAllComponent();
	}
	
}

void ASEntity::setMobileData(const ASEntityMobileData* pMobiledata)
{
	if (pMobiledata)
	{
		_vHeading = pMobiledata->_vHeading;
		_vSide = _vHeading.Perp();
		_dMass = pMobiledata->_dMass;
		_dMassInv = 1/_dMass;
		_dMaxSpeed = pMobiledata->_dMaxspeed;
		_dMaxForce = pMobiledata->_dMaxForce;
		_dMaxTurnRate = pMobiledata->_dMaxTurnRate;
	}
}

void ASEntity::addComponent(ASComponent* component)
{
	if (isComsLocked())
	{
		_vComsToAdd.push_back(component);
	}else
	{
		addComponentForce(component);
	}
	
}

void ASEntity::addComponentForce(ASComponent* component)
{
	int compName = component->getComName();
	std::set<int>::iterator it = _sComsRefuse.find(compName);
	if (it != _sComsRefuse.end())
	{
		return;//refuse to add this component
	}
	if (component->isMerge())
	{
		std::multimap<int,ASComponent*>::iterator it = _mComs.find(compName);
		if (it != _mComs.end())
		{
			it->second->merge(component);
			return;
		}
	}
	_mComs.insert(std::make_pair(compName,component));
	component->setHolder(this);
	component->onEnter();
}

ASComponent* ASEntity::getComponent(int compName)
{
	std::multimap<int,ASComponent*>::iterator it = _mComs.find(compName);
	if (it!=_mComs.end())
	{
		return it->second;
	}
	return nullptr;
}

bool ASEntity::removeComponent(int compName)
{
	if (isComsLocked())
	{
		std::multimap<int,ASComponent*>::iterator it = _mComs.find(compName);
		if (it!=_mComs.end())
		{
			it->second->setActive(false);
			return true;
		}
		return false;
	}
	else
	{
		return removeComponentForce(compName);
	}
}

bool ASEntity::removeComponentForce(int compName)
{
	std::multimap<int,ASComponent*>::iterator it = _mComs.find(compName);
	if (it!=_mComs.end())
	{
		if(it->second->getUpdateMatchFlag())
		{
			it->second->setUpdateMatchFlag(false);
			it->second->updateAfter();
		}
		it->second->onExit();
		delete it->second;
		_mComs.erase(it);
		return true;
	}
	return false;
}

void ASEntity::removeAllComponent()
{
	lockComs();
	for (std::multimap<int,ASComponent*>::reverse_iterator it=_mComs.rbegin();it!=_mComs.rend();it++)
	{
		if(it->second->getUpdateMatchFlag())
		{
			it->second->setUpdateMatchFlag(false);
			it->second->updateAfter();
		}
		it->second->onExit();
		delete it->second;
	}
	unlockComs();
	_mComs.clear();
	for(std::vector<ASComponent*>::iterator it = _vComsToAdd.begin();it != _vComsToAdd.end();it++)
	{
		delete *it;
	}
	_vComsToAdd.clear();
}

bool ASEntity::addRefuseComponent(int compName)
{
	std::set<int>::iterator it = _sComsRefuse.find(compName);
	if (it == _sComsRefuse.end())
	{
		_sComsRefuse.insert(compName);
		return true;
	}
	return false;
}
	
bool ASEntity::removeRefuseComponent(int compName)
{
	std::set<int>::iterator it = _sComsRefuse.find(compName);
	if (it != _sComsRefuse.end())
	{
		_sComsRefuse.erase(it);
		return true;
	}
	return false;
}

void ASEntity::entityUpdate(float dt)
{
	if(!_bActive)
		return;
	//add component
	for(std::vector<ASComponent*>::iterator it = _vComsToAdd.begin();it != _vComsToAdd.end();it++)
	{
		addComponentForce(*it);
	}
	_vComsToAdd.clear();

	ASComponent* pCom = nullptr;
	lockComs();
	std::multimap<int,ASComponent*>::iterator itCom;
	for (itCom=_mComs.begin();itCom!=_mComs.end();itCom++)
	{
		pCom = itCom->second;
		if(pCom->getActive())
		{
			pCom->setUpdateMatchFlag(true);
			pCom->updateBefore();
		}
	}
	for (itCom=_mComs.begin();itCom!=_mComs.end();itCom++)
	{
		pCom = itCom->second;
		if(pCom->getActive()&&pCom->getUpdateMatchFlag())
		{
			pCom->update(dt);
		}
	}
	unlockComs();
	update(dt);
	lockComs();
	for (std::multimap<int,ASComponent*>::reverse_iterator ritCom=_mComs.rbegin();ritCom!=_mComs.rend();ritCom++)
	{
		pCom = ritCom->second;
		if(/*pCom->getActive()&&*/pCom->getUpdateMatchFlag())
		{
			pCom->setUpdateMatchFlag(false);
			pCom->updateAfter();
		}
	}
	//delete component
	for (itCom=_mComs.begin();itCom!=_mComs.end();)
	{
		pCom = itCom->second;
		if(!pCom->getActive())
		{
			pCom->onExit();
			delete pCom;
			itCom = _mComs.erase(itCom);
		}
		else
		{
			itCom++;
		}
	}
	unlockComs();
	updateData();
}
void ASEntity::update(float dt)
{
}



NS_AS_END